﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.Xml;

namespace ChessOnline
{
    // Service description
    //[ServiceContract]
    //public interface ISwiftService
    //{
    //    [OperationContract]
    //    string Login(string id, string password);

    //    [OperationContract]
    //    bool Logout(string session_hash);

    //    [OperationContract]
    //    List<SendingAccount> GetAccountsInBank(string session_hash, string bank_name);

    //    [OperationContract]
    //    List<Transaction> GetTransactions(string session_hash, string account_id);

    //    [OperationContract]
    //    bool BlockUser(string session_hash, string account_id);

    //    [OperationContract]
    //    bool Transfer(string session_hash, string first_id, string second_id, string money);

    //    [OperationContract]
    //    bool AccountTransfer(string session_hash, string account_id, string bank_name);
    //}

    // Service implementation
    //public class SwiftService : ISwiftService
    //{
    //    private static string fileName = "..\\..\\SwiftDatabase.xml";
    //    // return hash-code string if login succeeded
    //    // return "-1" if can't login
    //    public string Login(string id, string password)
    //    {
    //        Console.WriteLine("Login called");
    //        string session_hash = "-1";

    //        try
    //        {
    //            XmlDocument doc = new XmlDocument();
    //            doc.Load(fileName);
    //            XmlNodeList xnList = doc.SelectNodes("/Database/Users/User"); // select all users in collection
    //            foreach (XmlNode xNode in xnList)
    //            {// for each user in users collection
    //                if (xNode.Attributes["id"].Value == id && xNode.Attributes["password"].Value == password)
    //                {// found user!
    //                    Random rnd = new Random((int)DateTime.Now.Ticks);
    //                    session_hash = rnd.Next().ToString() + "?" + id;
    //                    xNode.Attributes["session_hash"].Value = session_hash;
    //                    xNode.Attributes["is_online"].Value = "true";
    //                }
    //            }
    //            doc.Save(fileName);
    //            Console.WriteLine("Session hash sended: " + session_hash);
    //        }
    //        catch (Exception exc)
    //        {
    //            Console.WriteLine(exc.Message);
    //        }

    //        return session_hash;
    //    }

    //    public bool Logout(string session_hash)
    //    {
    //        try
    //        {
    //            XmlDocument doc = new XmlDocument();
    //            doc.Load(fileName);
    //            XmlNodeList xnList = doc.SelectNodes("/Database/Users/User"); // select all users in collection
    //            foreach (XmlNode xNode in xnList)
    //            {// for each user in users collection
    //                if (xNode.Attributes["session_hash"].Value == session_hash)
    //                {// found user!
    //                    Random rnd = new Random((int)DateTime.Now.Ticks);
    //                    session_hash = rnd.Next().ToString();
    //                    xNode.Attributes["session_hash"].Value = "";
    //                    xNode.Attributes["is_online"].Value = "false";
    //                }
    //            }
    //            doc.Save(fileName);
    //            Console.WriteLine("Session hash: " + session_hash + " terminated");
    //        }
    //        catch (Exception exc)
    //        {
    //            Console.WriteLine(exc.Message);
    //        }
    //        return true;
    //    }

    //    // returning list of accounts in bank with bank_name
    //    // return empty list if not found any or error occured
    //    public List<SendingAccount> GetAccountsInBank(string session_hash, string bank_name)
    //    {
    //        List<SendingAccount> list = new List<SendingAccount>();
    //        bool isUserValid = false;
    //        string bank_id = "";

    //        try
    //        {
    //            // validate user
    //            XmlDocument doc = new XmlDocument();
    //            doc.Load(fileName);
    //            XmlNodeList xnList = doc.SelectNodes("/Database/Users/User"); // select all users in collection
    //            foreach (XmlNode xNode in xnList)
    //            {// for each user in users collection
    //                if (xNode.Attributes["session_hash"].Value == session_hash)
    //                {// found user!
    //                    isUserValid = true;
    //                }
    //            }

    //            // find bank id
    //            if (isUserValid)
    //            {
    //                xnList = doc.SelectNodes("/Database/Banks/Bank");
    //                foreach (XmlNode xNode in xnList)
    //                {
    //                    if (xNode.Attributes["name"].Value == bank_name)
    //                    {// found bank!
    //                        bank_id = xNode.Attributes["id"].Value;
    //                    }
    //                }

    //                xnList = doc.SelectNodes("/Database/Accounts/Account");
    //                foreach (XmlNode xNode in xnList)
    //                {
    //                    if (xNode.Attributes["bank"].Value == bank_id)
    //                    {// found user from bank!
    //                        SendingAccount acc = new SendingAccount();
    //                        acc.id = xNode.Attributes["id"].Value;
    //                        acc.name = xNode.Attributes["name"].Value;
    //                        acc.surname = xNode.Attributes["surname"].Value;
    //                        list.Add(acc);
    //                    }
    //                }
    //            }
    //            // debug info
    //            Console.WriteLine("There is " + list.Count.ToString() + " accounts in " + bank_name + " bank.");
    //            //Console.WriteLine("First account:");
    //            //Console.WriteLine("id = " + list[0].id + " name = " + list[0].name + " surname = " + list[0].surname);
    //        }
    //        catch (Exception exc)
    //        {
    //            Console.WriteLine(exc.Message);
    //        }

    //        return list;
    //    }

    //    // returning list of transactions in account with account_id
    //    // return empty list if not found any or error occured
    //    public List<Transaction> GetTransactions(string session_hash, string account_id)
    //    {
    //        List<Transaction> list = new List<Transaction>();
    //        bool isUserValid = false;

    //        try
    //        {
    //            // validate user
    //            XmlDocument doc = new XmlDocument();
    //            doc.Load(fileName);
    //            XmlNodeList xnList = doc.SelectNodes("/Database/Users/User"); // select all users in collection
    //            foreach (XmlNode xNode in xnList)
    //            {// for each user in users collection
    //                if (xNode.Attributes["session_hash"].Value == session_hash)
    //                {// found user!
    //                    isUserValid = true;
    //                }
    //            }

    //            // find bank id
    //            if (isUserValid)
    //            {
    //                xnList = doc.SelectNodes("/Database/Transactions/Transaction");
    //                foreach (XmlNode xNode in xnList)
    //                {
    //                    if (xNode.Attributes["account"].Value == account_id)
    //                    {// found user from bank!
    //                        Transaction trans = new Transaction();
    //                        trans.date = xNode.Attributes["date"].Value;
    //                        trans.account = xNode.Attributes["account"].Value;
    //                        trans.action = xNode.Attributes["action"].Value;
    //                        trans.value = xNode.Attributes["value"].Value;
    //                        list.Add(trans);
    //                    }
    //                }
    //            }
    //            // debug info
    //            Console.WriteLine("There is " + list.Count.ToString() + " transactions in " + account_id + " account.");
    //        }
    //        catch (Exception exc)
    //        {
    //            Console.WriteLine(exc.Message);
    //        }

    //        return list;
    //    }

    //    public static void CloseAllConnections()
    //    {
    //        Console.WriteLine("Closing all connections...");

    //        try
    //        {
    //            XmlDocument doc = new XmlDocument();
    //            doc.Load(fileName);
    //            XmlNodeList xnList = doc.SelectNodes("/Database/Users/User"); // select all users in collection
    //            foreach (XmlNode xNode in xnList)
    //            {// for each user in users collection
    //                if (xNode.Attributes["is_online"].Value == "true")
    //                {// for all online users                        
    //                    xNode.Attributes["session_hash"].Value = "";
    //                    xNode.Attributes["is_online"].Value = "false";
    //                }
    //            }
    //            doc.Save(fileName);
    //            Console.WriteLine("Connection closed.");
    //        }
    //        catch (Exception exc)
    //        {
    //            Console.WriteLine(exc.Message);
    //        }
    //    }

    //    public bool BlockUser(string session_hash, string account_id)
    //    {
    //        bool result = false;
    //        bool isUserValid = false;

    //        try
    //        {
    //            // validate user
    //            XmlDocument doc = new XmlDocument();
    //            doc.Load(fileName);
    //            XmlNodeList xnList = doc.SelectNodes("/Database/Users/User"); // select all users in collection
    //            foreach (XmlNode xNode in xnList)
    //            {// for each user in users collection
    //                if (xNode.Attributes["session_hash"].Value == session_hash)
    //                {// found user!
    //                    isUserValid = true;
    //                }
    //            }

    //            // find bank id
    //            if (isUserValid)
    //            {
    //                xnList = doc.SelectNodes("/Database/Accounts/Account");
    //                foreach (XmlNode xNode in xnList)
    //                {
    //                    if (xNode.Attributes["id"].Value == account_id)
    //                    {// found account with given id
    //                        result = true;
    //                        xNode.Attributes["is_blocked"].Value = "true";
    //                    }
    //                }
    //                doc.Save(fileName);
    //            }
    //            // debug info
    //            Console.WriteLine("Account with id = " + account_id + " blocked.");
    //        }
    //        catch (Exception exc)
    //        {
    //            Console.WriteLine(exc.Message);
    //        }

    //        return result;
    //    }

    //    public bool Transfer(string session_hash, string first_id, string second_id, string money)
    //    {
    //        bool result = false;
    //        bool isUserValid = false;
    //        bool isFirstBlocked = false;
    //        bool isSecondBlocked = false;

    //        try
    //        {
    //            // validate user
    //            XmlDocument doc = new XmlDocument();
    //            doc.Load(fileName);
    //            XmlNodeList xnList = doc.SelectNodes("/Database/Users/User"); // select all users in collection
    //            foreach (XmlNode xNode in xnList)
    //            {// for each user in users collection
    //                if (xNode.Attributes["session_hash"].Value == session_hash)
    //                {// found user!
    //                    isUserValid = true;
    //                }
    //            }

    //            // if user valid
    //            if (isUserValid)
    //            {
    //                // check if first account is not blocked
    //                xnList = doc.SelectNodes("/Database/Accounts/Account");
    //                foreach (XmlNode xNode in xnList)
    //                {
    //                    if (xNode.Attributes["id"].Value == first_id)
    //                    {// found account with given id
    //                        if (xNode.Attributes["is_blocked"].Value == "true")
    //                        {
    //                            isFirstBlocked = true;
    //                        }
    //                    }
    //                }

    //                // check if second account is not blocked
    //                xnList = doc.SelectNodes("/Database/Accounts/Account");
    //                foreach (XmlNode xNode in xnList)
    //                {
    //                    if (xNode.Attributes["id"].Value == second_id)
    //                    {// found account with given id
    //                        if (xNode.Attributes["is_blocked"].Value == "true")
    //                        {
    //                            isSecondBlocked = true;
    //                        }
    //                    }
    //                }

    //                // if accounts are not blocked and exist
    //                if (isFirstBlocked == false && isSecondBlocked == false)
    //                {
    //                    // changes to first account (check if enough funds)
    //                    bool isEnoughFunds = false;
    //                    doc.Load(fileName);
    //                    xnList = doc.SelectNodes("/Database/Accounts/Account");
    //                    foreach (XmlNode xNode in xnList)
    //                    {
    //                        if (xNode.Attributes["id"].Value == first_id && Int32.Parse(xNode.Attributes["value"].Value) >= Int32.Parse(money))
    //                        {
    //                            isEnoughFunds = true;
    //                            xNode.Attributes["value"].Value = (Int32.Parse(xNode.Attributes["value"].Value) - Int32.Parse(money)).ToString();
    //                        }
    //                    }
    //                    doc.Save(fileName);

    //                    if (isEnoughFunds == true)
    //                    {
    //                        // changes to second account
    //                        doc.Load(fileName);
    //                        xnList = doc.SelectNodes("/Database/Accounts/Account");
    //                        foreach (XmlNode xNode in xnList)
    //                        {
    //                            if (xNode.Attributes["id"].Value == second_id)
    //                            {
    //                                xNode.Attributes["value"].Value = (Int32.Parse(xNode.Attributes["value"].Value) + Int32.Parse(money)).ToString();
    //                            }
    //                        }
    //                        doc.Save(fileName);

    //                        // find maximum id in transactions
    //                        int max_id = 0;
    //                        xnList = doc.SelectNodes("/Database/Transactions/Transaction");
    //                        foreach (XmlNode xNode in xnList)
    //                        {
    //                            int id = Int32.Parse(xNode.Attributes["id"].Value);
    //                            if (id > max_id)
    //                            {// found id more then current max 
    //                                max_id = id;
    //                            }
    //                        }

    //                        // add transaction to first account
    //                        int first_transaction_id = max_id + 1;
    //                        doc.Load(fileName);
    //                        XmlNode xMainNode = doc.SelectSingleNode("/Database/Transactions");
    //                        XmlNode xTransaction = doc.CreateElement("Transaction");
    //                        XmlAttribute xId = doc.CreateAttribute("id");
    //                        xId.InnerText = first_transaction_id.ToString();
    //                        XmlAttribute xDate = doc.CreateAttribute("date");
    //                        xDate.InnerText = DateTime.Now.ToString("dd.MM.yy");
    //                        XmlAttribute xAccount = doc.CreateAttribute("account");
    //                        xAccount.InnerText = first_id;
    //                        XmlAttribute xAction = doc.CreateAttribute("action");
    //                        xAction.InnerText = "outcome";
    //                        XmlAttribute xValue = doc.CreateAttribute("value");
    //                        xValue.InnerText = money;
    //                        xTransaction.Attributes.Append(xId);
    //                        xTransaction.Attributes.Append(xDate);
    //                        xTransaction.Attributes.Append(xAccount);
    //                        xTransaction.Attributes.Append(xAction);
    //                        xTransaction.Attributes.Append(xValue);
    //                        xMainNode.AppendChild(xTransaction);
    //                        doc.Save(fileName);

    //                        // add transaction to second account
    //                        int second_transaction_id = max_id + 2;
    //                        doc.Load(fileName);
    //                        xMainNode = doc.SelectSingleNode("/Database/Transactions");
    //                        xTransaction = doc.CreateElement("Transaction");
    //                        xId = doc.CreateAttribute("id");
    //                        xId.InnerText = second_transaction_id.ToString();
    //                        xDate = doc.CreateAttribute("date");
    //                        xDate.InnerText = DateTime.Now.ToString("dd.MM.yy");
    //                        xAccount = doc.CreateAttribute("account");
    //                        xAccount.InnerText = second_id;
    //                        xAction = doc.CreateAttribute("action");
    //                        xAction.InnerText = "income";
    //                        xValue = doc.CreateAttribute("value");
    //                        xValue.InnerText = money;
    //                        xTransaction.Attributes.Append(xId);
    //                        xTransaction.Attributes.Append(xDate);
    //                        xTransaction.Attributes.Append(xAccount);
    //                        xTransaction.Attributes.Append(xAction);
    //                        xTransaction.Attributes.Append(xValue);
    //                        xMainNode.AppendChild(xTransaction);
    //                        doc.Save(fileName);

    //                        result = true; // if everything went right we are completed operation
    //                    }
    //                    else
    //                    {
    //                        result = false;
    //                    }
    //                }
    //                else
    //                {
    //                    result = false;
    //                }
    //            }
    //            // debug info
    //            Console.WriteLine(first_id + " transfered funds to " + second_id + " : " + result.ToString());
    //        }
    //        catch (Exception exc)
    //        {
    //            Console.WriteLine(exc.Message);
    //        }
    //        return result;
    //    }

    //    public bool AccountTransfer(string session_hash, string account_id, string bank_name)
    //    {
    //        bool result = false;
    //        bool isUserValid = false;
    //        string bank_id = "";

    //        try
    //        {
    //            // validate user
    //            XmlDocument doc = new XmlDocument();
    //            doc.Load(fileName);
    //            XmlNodeList xnList = doc.SelectNodes("/Database/Users/User"); // select all users in collection
    //            foreach (XmlNode xNode in xnList)
    //            {// for each user in users collection
    //                if (xNode.Attributes["session_hash"].Value == session_hash)
    //                {// found user!
    //                    isUserValid = true;
    //                }
    //            }

    //            // find bank id
    //            if (isUserValid)
    //            {
    //                doc.Load(fileName);
    //                xnList = doc.SelectNodes("/Database/Banks/Bank");
    //                foreach (XmlNode xNode in xnList)
    //                {
    //                    if (xNode.Attributes["name"].Value == bank_name)
    //                    {// found account with given id
    //                        bank_id = xNode.Attributes["id"].Value;
    //                    }
    //                }

    //                if (bank_id != "")
    //                {// if bank has been found
    //                    doc.Load(fileName);
    //                    xnList = doc.SelectNodes("/Database/Accounts/Account");
    //                    foreach (XmlNode xNode in xnList)
    //                    {
    //                        if (xNode.Attributes["id"].Value == account_id)
    //                        {// found account with given id                            
    //                            result = true;
    //                            xNode.Attributes["bank"].Value = bank_id;
    //                        }
    //                    }
    //                    doc.Save(fileName);
    //                }
    //            }
    //            // debug info
    //            Console.WriteLine("Account with id = " + account_id + " transfered to bank with " + bank_id + " id.");
    //        }
    //        catch (Exception exc)
    //        {
    //            Console.WriteLine(exc.Message);
    //        }

    //        return result;
    //    }
    //}

    //// Working classes
    //public class User
    //{
    //    public int id { get; set; }
    //    public string password { get; set; }
    //    public string name { get; set; }
    //    public string surname { get; set; }
    //    public int bank { get; set; }
    //    public bool is_online { get; set; }
    //    public string session_hash { get; set; }
    //}

    //public class SendingAccount
    //{
    //    public string id { get; set; }
    //    public string name { get; set; }
    //    public string surname { get; set; }
    //}

    //public class Transaction
    //{
    //    public string date { get; set; }
    //    public string account { get; set; }
    //    public string action { get; set; }
    //    public string value { get; set; }
    //}

    // Hosting service in console
    class Program
    {
        static void Main(string[] args)
        {
            Uri baseAddress = new Uri("http://localhost:8732/"); // uri from which we can take service

            // Create the ServiceHost
            using (ServiceHost host = new ServiceHost(typeof(ChessOnlineService), baseAddress))
            {
                // Enable metadata publishing.
                host.AddServiceEndpoint(typeof(IChessOnlineService), new BasicHttpBinding(), "services");
                host.AddServiceEndpoint(typeof(IPolicyRetriever), new WebHttpBinding(), "").Behaviors.Add(new WebHttpBehavior());
                ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
                smb.HttpGetEnabled = true;
                smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
                host.Description.Behaviors.Add(smb);
                ServiceThrottlingBehavior stb = new ServiceThrottlingBehavior();
                stb.MaxConcurrentCalls = 20;
                stb.MaxConcurrentInstances = 20;
                stb.MaxConcurrentSessions = 20;
                host.Description.Behaviors.Add(stb);

                // Open the ServiceHost to start listening for messages. Since
                // no endpoints are explicitly configured, the runtime will create
                // one endpoint per base address for each service contract implemented
                // by the service.
                host.Open();

                Console.WriteLine("The service is ready at {0}", baseAddress);
                Console.WriteLine("Press <Enter> to stop the service.");
                ChessOnlineService.LoadUsersDatabase();
                Console.ReadLine();

                // Close all connections                
                ChessOnlineService.CloseAllConnections();
                //ChessOnlineService.SaveUsersDatabase(); // TODO: uncomment this!

                // Close the ServiceHost
                host.Close();
            }
        }
    }
}
